package dji.sampleV5.aircraft.models

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import dji.sampleV5.aircraft.DJIAircraftApplication
import dji.sampleV5.aircraft.data.DJIToastResult
import dji.sampleV5.aircraft.listener.SimpleMediaFileDownloadListener
import dji.sampleV5.aircraft.upload.UploadWork
import dji.sampleV5.aircraft.util.ToastUtils
import dji.sdk.keyvalue.key.CameraKey
import dji.sdk.keyvalue.key.KeyTools
import dji.sdk.keyvalue.key.KeyTools.createKey
import dji.sdk.keyvalue.value.camera.CameraMode
import dji.sdk.keyvalue.value.camera.CameraStorageLocation
import dji.sdk.keyvalue.value.common.ComponentIndexType
import dji.sdk.keyvalue.value.media.MediaFileList
import dji.v5.common.callback.CommonCallbacks
import dji.v5.common.error.IDJIError
import dji.v5.common.error.RxError
import dji.v5.common.utils.CallbackUtils
import dji.v5.common.utils.RxUtil
import dji.v5.manager.KeyManager
import dji.v5.manager.datacenter.MediaDataCenter
import dji.v5.manager.datacenter.media.MediaFile
import dji.v5.manager.datacenter.media.MediaFileDownloadListener
import dji.v5.manager.datacenter.media.MediaFileListData
import dji.v5.manager.datacenter.media.MediaFileListDataSource
import dji.v5.manager.datacenter.media.MediaFileListState
import dji.v5.manager.datacenter.media.MediaFileListStateListener
import dji.v5.manager.datacenter.media.PullMediaFileListParam
import dji.v5.utils.common.ContextUtil
import dji.v5.utils.common.DiskUtil
import dji.v5.utils.common.LogUtils
import dji.v5.utils.common.StringUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
import java.text.ParseException

/**
 * @author feel.feng
 * @time 2022/04/20 2:19 下午
 * @description: 媒体回放下载数据
 */
class MediaVM : DJIViewModel() {
    var mediaFileListData = MutableLiveData<MediaFileListData>()
    var fileListState = MutableLiveData<MediaFileListState>()
    var isPlayBack = MutableLiveData<Boolean?>()
    private val tag = javaClass.simpleName
    private val mediaFileList = mutableListOf<MediaFile>()
    lateinit var dirs:File
    var dd =0
    fun init() {
        //addMediaFileListStateListener()
        LogUtils.e(logTag, "init_test_1")
        mediaFileListData.value = MediaDataCenter.getInstance().mediaManager.mediaFileListData
        mediaFileList.addAll(getMediaFileList())
        MediaDataCenter.getInstance().mediaManager.addMediaFileListStateListener { mediaFileListState ->
            LogUtils.e(logTag, "init_test_1"+mediaFileListState)
            if (mediaFileListState == MediaFileListState.UP_TO_DATE) {
                val data = MediaDataCenter.getInstance().mediaManager.mediaFileListData;
                mediaFileListData.postValue(data)


//                LogUtils.e(logTag, "init_test_1：进来了")
//                LogUtils.e(logTag, "init_test_a:"+data.data.get(0).a)//0
//                LogUtils.e(logTag, "init_test_b:"+data.data.get(0).b)//0
//                LogUtils.e(logTag, "init_test_c:"+data.data.get(0).c)//null
//                LogUtils.e(logTag, "init_test_d:"+data.data.get(0).d)//UNKNOWN
//                LogUtils.e(logTag, "init_test_e:"+data.data.get(0).e)//[]
//                LogUtils.e(logTag, "init_test_f:"+data.data.get(0).f)//null
//                LogUtils.e(logTag, "init_test_g:"+data.data.get(0).g)//false
//                LogUtils.e(logTag, "init_test_h:"+data.data.get(0).h)//false
//                LogUtils.e(logTag, "init_test_i:"+data.data.get(0).i)//有可能是高度28.9 == 29
//                LogUtils.e(logTag, "init_test_j:"+data.data.get(0).j)//null
//                LogUtils.e(logTag, "init_test_k:"+data.data.get(0).k)//null
//                LogUtils.e(logTag, "init_test_l:"+data.data.get(0).l)//null
//                LogUtils.e(logTag, "init_test_m:"+data.data.get(0).m)//null
//
//                LogUtils.e(logTag, "init_test_ca:"+data.data.get(0).co_a)//MediaFile
//                LogUtils.e(logTag, "init_test_cb:"+data.data.get(0).co_b)//null
//                LogUtils.e(logTag, "init_test_cc:"+data.data.get(0).co_c)//dji.v5.utils.common.XMLUtil$MutablePair@d95cfa8
//                LogUtils.e(logTag, "init_test_cd:"+data.data.get(0).co_d)//false
//                LogUtils.e(logTag, "init_test_ce:"+data.data.get(0).co_e)//false
//                LogUtils.e(logTag, "init_test_cf:"+data.data.get(0).co_f)//7602377
//                LogUtils.e(logTag, "init_test_cg:"+data.data.get(0).co_g)//文件格式 JPEG
//                LogUtils.e(logTag, "init_test_ch:"+data.data.get(0).co_h)//文件名字 DJI_20240402210823_0012_V.JPG
//                LogUtils.e(logTag, "init_test_ci:"+data.data.get(0).co_i)//7831552
//                LogUtils.e(logTag, "init_test_cj:"+data.data.get(0).co_j)//拍摄时间{“year”:2024,"month":4."day","hour","minute","second"}
//                LogUtils.e(logTag, "init_test_ck:"+data.data.get(0).co_k)//UNKNOWN
//                LogUtils.e(logTag, "init_test_cl:"+data.data.get(0).co_l)//false
//                LogUtils.e(logTag, "init_test_cm:"+data.data.get(0).co_m)//0
//                LogUtils.e(logTag, "init_test_cn:"+data.data.get(0).co_n)//UNKNOWN
//                LogUtils.e(logTag, "init_test_co:"+data.data.get(0).co_o)//UNKNOWN
//                LogUtils.e(logTag, "init_test_cp:"+data.data.get(0).co_p)//UNKNOWN
//                LogUtils.e(logTag, "init_test_cq:"+data.data.get(0).co_q)//UNKNOWN
//                LogUtils.e(logTag, "init_test_cr:"+data.data.get(0).co_r)//UNKNOWN
//                LogUtils.e(logTag, "init_test_cs:"+data.data.get(0).co_s)//UNKNOWN
//                LogUtils.e(logTag, "init_test_ct:"+data.data.get(0).co_t)//UNKNOWN
//                LogUtils.e(logTag, "init_test_cu:"+data.data.get(0).co_u)//0
//                LogUtils.e(logTag, "init_test_cv:"+data.data.get(0).co_v)//0
//                LogUtils.e(logTag, "init_test_cw:"+data.data.get(0).co_w)//false
//                LogUtils.e(logTag, "init_test_cx:"+data.data.get(0).co_x)//0
//                LogUtils.e(logTag, "init_test_cy:"+data.data.get(0).co_y)//0
//                LogUtils.e(logTag, "init_test_cz:"+data.data.get(0).co_z)//0
//
//                LogUtils.e(logTag, "init_test_cz1:"+data.data.get(0).orientation)
//                LogUtils.e(logTag, "init_test_cz2:"+data.data.get(0).exifInfo)
//                LogUtils.e(logTag, "init_test_cz3:"+data.data.get(0).dcfInfo)
//                LogUtils.e(logTag, "init_test_cz4:"+data.data.get(0).isCloudDownload)
//                LogUtils.e(logTag, "init_test_cz5:"+data.data.get(0).isHasOriginalFile)
//                LogUtils.e(logTag, "init_test_cz6xmp:"+data.data.get(0).xmpFileData)
//                LogUtils.e(logTag, "init_test_cz6xmp:"+data.data.get(0).xmpFileData.get(5))
                //LogUtils.e(logTag, "init_test_cz6xmp:"+data.data.get(0).xmpFileData.get(10))
                //LogUtils.e(logTag, "init_test_cz6xmp:"+data.data.get(0).xmpCustomInfo.get(0))

                if(dd>0) {
                    downloadFiles(data)
                }else{
                    mediaFileList.addAll(data.data)
                }
                dd = dd + 1
                LogUtils.e(logTag, "init_test_d:"+dd)
            }
        }
        pullMediaFileListFromCamera(1, 1)//从mediafileindex开始往后拉取count个文件
        LogUtils.e(logTag, "init_test_2")
        //mediaFileListData.value = MediaDataCenter.getInstance().mediaManager.mediaFileListData
        //mediaFileList.addAll(getMediaFileList())
        //LogUtils.e(logTag, "init_test_2:"+mediaFileList.size)
    }

    fun destroy() {
        KeyManager.getInstance().cancelListen(this);
        removeAllFileListStateListener()

        MediaDataCenter.getInstance().mediaManager.release()
    }

    fun pullMediaFileListFromCamera(mediaFileIndex: Int, count: Int) {
        var currentTime = System.currentTimeMillis()
        MediaDataCenter.getInstance().mediaManager.pullMediaFileListFromCamera(
            PullMediaFileListParam.Builder().mediaFileIndex(mediaFileIndex).count(count).build(),
            object :
                CommonCallbacks.CompletionCallback {
                override fun onSuccess() {
                    ToastUtils.showToast("Spend time:${(System.currentTimeMillis() - currentTime) / 1000}s")
                    LogUtils.i(logTag, "fetch success")
                }

                override fun onFailure(error: IDJIError) {
                    LogUtils.e(logTag, "fetch failed$error")
                }
            })
    }

    fun pullXMPFileDataFromCamera(mediaFileIndex: Int, count: Int) {
        var currentTime = System.currentTimeMillis()
        MediaDataCenter.getInstance().mediaManager.pullMediaFileListFromCamera(
                PullMediaFileListParam.Builder().mediaFileIndex(mediaFileIndex).count(count).build(),
                object :
                        CommonCallbacks.CompletionCallback {
                    override fun onSuccess() {
                        ToastUtils.showToast("Spend time:${(System.currentTimeMillis() - currentTime) / 1000}s")
                        LogUtils.i(logTag, "fetch success")
                    }

                    override fun onFailure(error: IDJIError) {
                        LogUtils.e(logTag, "fetch failed$error")
                    }
                })
    }

    private fun addMediaFileListStateListener() {
        MediaDataCenter.getInstance().mediaManager.addMediaFileListStateListener(object :
            MediaFileListStateListener {
            override fun onUpdate(mediaFileListState: MediaFileListState) {
                fileListState.postValue(mediaFileListState)
            }

        })
    }

    private fun removeAllFileListStateListener() {
        MediaDataCenter.getInstance().mediaManager.removeAllMediaFileListStateListener()
    }

    private fun downloadFiles(data: MediaFileListData) {
        var dd = 0
        //1. 筛选最新拍的那张图片
        LogUtils.e(tag, "init_download=进入1")
        val result = data.data - mediaFileList.toSet()
        LogUtils.e(tag, "init_download="+data.data.size)
        LogUtils.e(tag, "init_download="+mediaFileList.size)
        mediaFileList.clear()
        mediaFileList.addAll(data.data)
        LogUtils.e(tag, "init_download=$result")
        //2. 从无人机download file
        val downloadFileList = arrayListOf<MediaFile>()
        downloadFileList.addAll(result)
        downloadMediaFile(downloadFileList, object : SimpleMediaFileDownloadListener() {
            override fun onFinish() {
                LogUtils.e(tag, "init_download=进入2")
                uploadFiles(result)
                LogUtils.e(tag, "init_download=进入2:"+dd)
            }
        })
    }
    private fun uploadFiles(result: List<MediaFile>) {
        viewModelScope.launch(Dispatchers.IO) {
            LogUtils.e(tag, "init_upload=进入1")
            val filePathList = mutableListOf<String>()
            LogUtils.e(tag, "init_upload=进入2")
            result.forEach {
                LogUtils.e(tag, "init_upload=进入3")
                filePathList.add(dirs.toString()+"/"+it.fileName) //TODO: 看看MediaFile里哪个是路径，替换成路径
                LogUtils.e(tag, "init_upload=进入3"+dirs.toString())
                LogUtils.e(tag, "init_upload=进入3"+it.fileName)
            }
            if (filePathList.isNotEmpty()) {
                LogUtils.e(tag, "init_upload=进入4")/////以下出错
                //if(DJIAircraftApplication.application.is)
                val appContext = DJIAircraftApplication.application.applicationContext
                LogUtils.e(tag, "init_upload=进入5")
                UploadWork.startWork(appContext, filePathList)
                LogUtils.e(tag, "init_upload=进入6")

            }
        }
    }

    fun getMediaFileList(): List<MediaFile> {
        return mediaFileListData.value?.data?: emptyList()
    }

    fun setMediaFileXMPCustomInfo(info: String) {
        MediaDataCenter.getInstance().mediaManager.setMediaFileXMPCustomInfo(info, object :
            CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                toastResult?.postValue(DJIToastResult.success())
            }

            override fun onFailure(error: IDJIError) {
                toastResult?.postValue(DJIToastResult.failed(error.toString()))
            }
        })
    }

    fun getMediaFileXMPCustomInfo() {
        MediaDataCenter.getInstance().mediaManager.getMediaFileXMPCustomInfo(object :
            CommonCallbacks.CompletionCallbackWithParam<String> {
            override fun onSuccess(s: String) {
                toastResult?.postValue(DJIToastResult.success(s))
            }

            override fun onFailure(error: IDJIError) {
                toastResult?.postValue(DJIToastResult.failed(error.toString()))
            }
        })
    }

    fun setComponentIndex(index: ComponentIndexType) {
        isPlayBack.postValue(false)
        KeyManager.getInstance().cancelListen(this)
        KeyManager.getInstance().listen(
            KeyTools.createKey(
                CameraKey.KeyIsPlayingBack, index
            ), this
        ) { _, newValue ->
            isPlayBack.postValue(newValue)
        }
        val mediaSource = MediaFileListDataSource.Builder().setIndexType(index).build()
        MediaDataCenter.getInstance().mediaManager.setMediaFileDataSource(mediaSource)
    }

    fun setStorage(location: CameraStorageLocation) {
        val mediaSource = MediaFileListDataSource.Builder().setLocation(location).build()
        MediaDataCenter.getInstance().mediaManager.setMediaFileDataSource(mediaSource)
    }

    fun enable() {
        LogUtils.e(logTag, "init_test_3")
        MediaDataCenter.getInstance().mediaManager.enable(object :
            CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                LogUtils.e(logTag, "init_test_enable playback success")
            }

            override fun onFailure(error: IDJIError) {
                LogUtils.e(logTag, "init_test_error is ${error.description()}")
            }
        })
        LogUtils.e(logTag, "init_test_4")
    }

    fun disable() {
        MediaDataCenter.getInstance().mediaManager.disable(object :
            CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                LogUtils.e(logTag, "exit playback success")
            }

            override fun onFailure(error: IDJIError) {
                LogUtils.e(logTag, "error is ${error.description()}")
            }
        })
    }

    fun takePhoto(callback: CommonCallbacks.CompletionCallback) {
        RxUtil.setValue(createKey<CameraMode>(
            CameraKey.KeyCameraMode), CameraMode.PHOTO_NORMAL)
            .andThen(RxUtil.performActionWithOutResult(createKey(CameraKey.KeyStartShootPhoto)))
            .subscribe({ CallbackUtils.onSuccess(callback) }
            ) { throwable: Throwable ->
                CallbackUtils.onFailure(
                    callback,
                    (throwable as RxError).djiError
                )
            }
    }

    //?= null
    fun  downloadMediaFile(mediaList : ArrayList<MediaFile>, downloadListener: SimpleMediaFileDownloadListener){
        mediaList.forEach {
            downloadFile(it, downloadListener)
        }
    }
    fun  downloadMediaFile(mediaList : ArrayList<MediaFile>){
        mediaList.forEach {
            downloadFile(it)
        }
    }

    private fun downloadFile(mediaFile :MediaFile, downloadListener: SimpleMediaFileDownloadListener) {
        dirs = File(DiskUtil.getExternalCacheDirPath(ContextUtil.getContext(),  "/mediafile"))
        if (!dirs.exists()) {
            dirs.mkdirs()
        }
        val filepath = DiskUtil.getExternalCacheDirPath(ContextUtil.getContext(),  "/mediafile/"  + mediaFile?.fileName)
        val file = File(filepath)
        var offset = 0L
        val outputStream = FileOutputStream(file, true)
        val bos = BufferedOutputStream(outputStream)
        mediaFile?.pullOriginalMediaFileFromCamera(offset, object : MediaFileDownloadListener {
            override fun onStart() {
                LogUtils.i("MediaFile" , "${mediaFile.fileIndex } start download"  )
                downloadListener?.onStart()
            }

            override fun onProgress(total: Long, current: Long) {
                val fullSize = offset + total;
                val downloadedSize = offset + current
                val data: Double = StringUtils.formatDouble((downloadedSize.toDouble() / fullSize.toDouble()))
                val result: String = StringUtils.formatDouble(data * 100, "#0").toString() + "%"
                LogUtils.i("MediaFile"  , "${mediaFile.fileIndex}  progress $result")
                downloadListener?.onProgress(total, current)
            }

            override fun onRealtimeDataUpdate(data: ByteArray, position: Long) {
                try {
                    bos.write(data)
                    bos.flush()
                    downloadListener?.onRealtimeDataUpdate(data, position)
                } catch (e: IOException) {
                    LogUtils.e("MediaFile", "write error" + e.message)
                }
            }

            override fun onFinish() {
                try {
                    outputStream.close()
                    bos.close()
                    downloadListener?.onFinish()
                } catch (error: IOException) {
                    LogUtils.e("MediaFile", "close error$error")
                }
                LogUtils.i("MediaFile" , "${mediaFile.fileIndex }  download finish"  )
            }

            override fun onFailure(error: IDJIError?) {
                LogUtils.e("MediaFile", "download error$error")
                downloadListener?.onFailure(error)
            }

        })
    }

    private fun downloadFile(mediaFile :MediaFile ) {
        val dirs = File(DiskUtil.getExternalCacheDirPath(ContextUtil.getContext(),  "/mediafile"))
        if (!dirs.exists()) {
            dirs.mkdirs()
        }
        val filepath = DiskUtil.getExternalCacheDirPath(ContextUtil.getContext(),  "/mediafile/"  + mediaFile?.fileName)
        val file = File(filepath)
        var offset = 0L
        val outputStream = FileOutputStream(file, true)
        val bos = BufferedOutputStream(outputStream)
        mediaFile?.pullOriginalMediaFileFromCamera(offset, object : MediaFileDownloadListener {
            override fun onStart() {
                LogUtils.i("MediaFile" , "${mediaFile.fileIndex } start download"  )
            }

            override fun onProgress(total: Long, current: Long) {
                val fullSize = offset + total;
                val downloadedSize = offset + current
                val data: Double = StringUtils.formatDouble((downloadedSize.toDouble() / fullSize.toDouble()))
                val result: String = StringUtils.formatDouble(data * 100, "#0").toString() + "%"
                LogUtils.i("MediaFile"  , "${mediaFile.fileIndex}  progress $result")
            }

            override fun onRealtimeDataUpdate(data: ByteArray, position: Long) {
                try {
                    bos.write(data)
                    bos.flush()
                } catch (e: IOException) {
                    LogUtils.e("MediaFile", "write error" + e.message)
                }
            }

            override fun onFinish() {
                try {
                    outputStream.close()
                    bos.close()
                } catch (error: IOException) {
                    LogUtils.e("MediaFile", "close error$error")
                }
                LogUtils.i("MediaFile" , "${mediaFile.fileIndex }  download finish"  )
            }

            override fun onFailure(error: IDJIError?) {
                LogUtils.e("MediaFile", "download error$error")
            }

        })
    }
}